package top.zhangjianyong.blog.utils;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import org.springframework.beans.BeanUtils;
import top.zhangjianyong.blog.enums.RespCode;
import top.zhangjianyong.blog.entity.dto.TreeNodeDTO;
import top.zhangjianyong.blog.exception.ApiException;
import top.zhangjianyong.blog.record.DelAndAdd;

/**
 * 实体对象工具类
 *
 * @author zhangjianyong
 * @since 2024/7/25 上午9:45
 */
public class EntityUtil {

  public static <T> DelAndAdd<T> getDelAndAdd(List<T> oldList, List<T> newList) {
    Set<T> del = oldList.stream().filter(o -> !newList.contains(o)).collect(Collectors.toSet());
    Set<T> add = newList.stream().filter(o -> !oldList.contains(o)).collect(Collectors.toSet());
    return new DelAndAdd<>(del, add);
  }

  public static <T, U extends T> U entity2DTO(T t, Class<U> clazz)
      throws InstantiationException,
          IllegalAccessException,
          NoSuchMethodException,
          InvocationTargetException {
    U u = clazz.getDeclaredConstructor().newInstance();
    BeanUtils.copyProperties(t, u);
    return u;
  }

  public static <T, U extends T> List<U> entity2DTO(List<T> list, Class<U> clazz) {
    return list.stream()
        .map(
            t -> {
              try {
                return entity2DTO(t, clazz);
              } catch (InstantiationException
                  | IllegalAccessException
                  | NoSuchMethodException
                  | InvocationTargetException e) {
                // 实体转换异常，抛出自定义 ApiException，便于全局异常处理
                throw new ApiException(RespCode.FAIL, e);
              }
            })
        .collect(Collectors.toList());
  }

  public static <T extends TreeNodeDTO<T>> List<T> toTree(List<? extends T> list) {
    Map<Long, TreeNodeDTO<T>> map =
        list.stream().collect(Collectors.toMap(TreeNodeDTO::getId, o -> o, (a, b) -> a));
    List<T> result = new ArrayList<>();
    for (T treeNodeDTO : list) {
      Long pid = treeNodeDTO.getPid();
      // 没有父节点放入result list
      if (null == pid || 0 == pid) {
        result.add(treeNodeDTO);
      } else {
        // 去除父节点
        TreeNodeDTO<T> node = map.get(pid);
        if (null == node) continue;
        List<T> children = node.getChildren();
        // 父节点子节点list为null创建
        if (children == null) {
          children = new ArrayList<>();
          node.setChildren(children);
        }
        children.add(treeNodeDTO);
      }
    }
    return result;
  }
}
